package com.jfs.config;

import com.jfs.expand.CustomThreadPoolTaskExecutor;
import com.jfs.factory.BeatThreadFactory;
import com.jfs.factory.SessionThreadFactory;
import com.jfs.health.HealthCheckReactor;
import com.jfs.properties.BeatExecutorProperties;
import com.jfs.properties.TaskExecutorProperties;
import com.jfs.security.properties.SessionExecutorProperties;
import com.jfs.security.session.SessionCleanReactor;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Description 线程池配置
 * @E-mail cwm3412638@163.com
 * @Author cwm
 * @Date 2022-08-23
 */
@Configuration
@Data
@AllArgsConstructor
@EnableAsync(proxyTargetClass = true)
@EnableConfigurationProperties(value = {TaskExecutorProperties.class, BeatExecutorProperties.class})
public class TaskExecutorConfig {
    /**
     * 配置自定义线程池
     *
     * @return
     */
    @Bean
    public TaskExecutor taskExecutor(TaskExecutorProperties taskExecutorProperties) {
        ThreadPoolTaskExecutor executor = new CustomThreadPoolTaskExecutor();
        executor.setCorePoolSize(taskExecutorProperties.getCorePoolSize());
        executor.setMaxPoolSize(taskExecutorProperties.getMaxPoolSize());
        executor.setQueueCapacity(taskExecutorProperties.getQueueCapacity());
        executor.setThreadNamePrefix(taskExecutorProperties.getThreadNamePrefix());
        /*
           rejection-policy：当pool已经达到max size的时候，如何处理新任务
           CALLER_RUNS：不在新线程中执行任务，而是有调用者所在的线程来执行
        */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

    /**
     * 配置心跳检查线程池
     *
     * @param beatExecutorProperties
     * @return
     */
    @Bean
    public ScheduledExecutorService beatExecutor(BeatExecutorProperties beatExecutorProperties) {
        return Executors.newScheduledThreadPool(beatExecutorProperties.getCorePoolSize(),
                new BeatThreadFactory(beatExecutorProperties.getThreadNamePrefix()));
    }

    /**
     * 心跳管理者
     *
     * @param scheduledExecutorService
     * @return
     */
    @Bean
    public HealthCheckReactor healthCheckReactor(@Qualifier("beatExecutor") ScheduledExecutorService scheduledExecutorService) {
        return new HealthCheckReactor(scheduledExecutorService);
    }

    /**
     * 配置过期会话清理线程池
     *
     * @param sessionExecutorProperties
     * @return
     */
    @Bean
    public ScheduledExecutorService sessionExecutor(SessionExecutorProperties sessionExecutorProperties) {
        return Executors.newScheduledThreadPool(sessionExecutorProperties.getCorePoolSize(),
                new SessionThreadFactory(sessionExecutorProperties.getThreadNamePrefix()));
    }

    /**
     * 会话管理者
     *
     * @param scheduledExecutorService
     * @return
     */
    @Bean
    public SessionCleanReactor sessionCleanReactor(@Qualifier("sessionExecutor") ScheduledExecutorService scheduledExecutorService) {
        return new SessionCleanReactor(scheduledExecutorService);
    }
}
